package com.cwnu.sw.cys.core.user.service.impl;

import com.cwnu.sw.cys.core.common.constant.RedisKey;
import com.cwnu.sw.cys.core.user.service.LoginService;
import com.cwnu.sw.cys.core.common.utils.JwtUtils;
import com.cwnu.sw.cys.core.common.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author jisam
 * @version 1.0
 * @contact "jisamchan@outlook.com"
 * @date 17/02/2025
 * @description
 */
@Service
public class LoginServiceImpl implements LoginService {

    public static final int TOKEN_EXPIRE_DAYS = 3;
    public static final int IF_EXPIRED = -2;
    @Autowired
    private JwtUtils jwtUtils;

    /**
     * @param token
     * @return
     */
    @Override
    public boolean verify(String token) {
       Long validUid = getValidUid(token);
       if (Objects.isNull(validUid)){
           return false;
       }
       String key = RedisKey.getKey(RedisKey.USER_TOKEN_STRING,validUid);
       String tokenInRedis = RedisUtils.getStr(key);
       return Objects.equals(tokenInRedis, token);
    }

    /**
     * @param token
     */
    @Override
    @Async
    public void renewalTokenIfNecessary(String token) {
        Long validUid = getValidUid(token);
        if (Objects.isNull(validUid)) {
            return;
        }
        String userTokenKey = getUserTokenKey(validUid);
        Long expireDays = RedisUtils.getExpire(userTokenKey, TimeUnit.DAYS);
        if(expireDays == IF_EXPIRED){
            return ;
        }
        if(expireDays < TOKEN_EXPIRE_DAYS){
            RedisUtils.expire(userTokenKey, TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
        }
    }


    /**
     * @param uid
     * @return
     */
    @Override
    public String login(Long uid) {
        String token = jwtUtils.createToken(uid);
        RedisUtils.set(RedisKey.getKey(RedisKey.USER_TOKEN_STRING,uid),token , TOKEN_EXPIRE_DAYS, TimeUnit.DAYS );
        return token;

    }

    /**
     * 根据Token验证用户身份有效性并返回有效UID
     *
     * @param token 用户身份验证令牌，需包含用户身份信息
     * @return 当token有效且未过期时返回用户ID，无效/过期返回null
     */
    @Override
    public Long getValidUid(String token) {
        // 从JWT中解析用户ID（允许返回null）
        Long uid = jwtUtils.getUidOrNull(token);

        // 检查JWT解析结果有效性
        if(Objects.isNull(uid)){
            return null;
        }

        // 从Redis获取该用户最近的有效token进行比对
        String tokenInRedis = RedisUtils.getStr(getUserTokenKey(uid));
        return Objects.equals(tokenInRedis, token) ? uid :null;
    }

    /**
     * 生成用户token在Redis中的存储键
     *
     * @param uid 用户ID
     * @return 包含用户ID的完整Redis键字符串
     */
    private String getUserTokenKey(Long uid) {
        return RedisKey.getKey(RedisKey.USER_TOKEN_STRING,uid);
    }

}
